package cn.nju.seg.atg.GA;

public abstract  class StringGA extends Population
{
    /** 
     * 用Sring类型存储一个浮点数时，小数点在该实数中的位置。
     */
    protected int chromDecPts;

    /** 
     * 每个基因可取的字符值. 
     * 例如, 如果possGeneValues为"01"，那么一个基因可以为"0"或“1”。
     */
    private String possGeneValues = "01";

    /**
     * 返回个体序列中的某个个体
     * @param index
     * @return CharsChromosome
     */
    protected CharsChromosome getChromosome(int index){
        return ((CharsChromosome) this.chromosomes[index]);
    }

    /**
     * 初始化
     * @param chromosomeDim
     * @param populationDim
     * @param crossoverProb
     * @param randomSelectionChance
     * @param maxGenerations
     * @param numPrelimRuns
     * @param maxPrelimGenerations
     * @param mutationProb
     * @param chromDecPts
     * @param crossoverType
     * @param computeStatistics
     * @throws GAException
     */
    public StringGA(int chromosomeDim,
                    int populationDim,
                    double crossoverProb,
                    int randomSelectionChance,
                    int maxGenerations,
                    int numPrelimRuns,
                    int maxPrelimGenerations,
                    double mutationProb,
                    int chromDecPts,
                    int crossoverType,
                    boolean computeStatistics)
                    {
        super(chromosomeDim,
              populationDim,
              crossoverProb,
              randomSelectionChance,
              maxGenerations,
              numPrelimRuns,
              maxPrelimGenerations,
              mutationProb,
              crossoverType,
              computeStatistics);

        this.chromDecPts = chromDecPts;

        //为参与遗传进化的种群分配空间
        for (int i = 0; i < populationDim; i++){
            this.chromosomes[i] = new CharsChromosome(chromosomeDim);
            this.chromNextGen[i] = new CharsChromosome(chromosomeDim);
            this.prelimChrom[i] = new CharsChromosome(chromosomeDim);
        }

        initPopulation();
    }

    /**
     * float or binary?
     * @param sChromosome
     * @param iNumDecPts
     * @return double
     */
    protected double chromStrToFloat(String sChromosome, int iNumDecPts){
        String sFloat;
        int iLen;
   
        if (iNumDecPts == 0)
            return (binaryStrToInt(sChromosome));
        else{
        	 //将一个以字符串表示的实数转换为double类型的实值
             // 例如, 如果 sChromosome = "01234" 并且 iNumDecPts = 4, 那么将返回 0.1234
            iLen = sChromosome.length() - iNumDecPts;
            sFloat = sChromosome.substring(0, iLen) + "." +
                     sChromosome.substring(iLen, iLen + iNumDecPts);
            return (Double.parseDouble(sFloat));
        }
    }

    /**
     * 当一个染色体表示多个参数时，将一个String类型的染色体转换为double类型的数组。
     * @param sChromosome
     * @return double[]
     * @throws GAException 
     */
/*    public static double[] getChromValAsDoubleArray(String sChromosome) {
    	long digit;

    	double[] parameters = new double[ATG.NUM_OF_PARAM];
    	
    	for(int i = ATG.NUM_OF_PARAM;i > 0;i--){
			for(int j = ATG.PARAM_LENGTH * i-1;j>=ATG.PARAM_LENGTH * (i-1);j--){
		            if (sChromosome.charAt(j) == '1')
		                digit = 1;
		            else
		                digit = 0;
		            parameters[i-1] += (digit << (ATG.PARAM_LENGTH*i - j - 1));
		    }
    	}
        
        return parameters; 		
    }
*/  
    /**
     * 将String型的染色体转换为double型
     * @param sChromosome
     * @return double
     */
    protected double getChromValAsDouble(String sChromosome){
        return (chromStrToFloat(sChromosome, this.chromDecPts));
    }

    /**
     * 从possGeneValues中随机选取一个可能的基因值
     * @return char
     */
    protected char getRandomGeneFromPossGenes(){
        int iRandomIndex = getRandom(this.possGeneValues.length());
        return (this.possGeneValues.charAt(iRandomIndex));
    }

    /**
     * 变异操作，为给定的染色体随机交换它的基因序列中的某两位
     * @param iChromIndex
     */
    @Override
    protected void doRandomMutation(int iChromIndex){
        int iGene1, iGene2;
        char cTemp;

        iGene1 = getRandom(chromosomeDim);
        iGene2 = getRandom(chromosomeDim);

        cTemp = ((CharsChromosome) this.chromosomes[iChromIndex]).genes[iGene1];
        ((CharsChromosome) this.chromosomes[iChromIndex]).genes[iGene1] =
                                        ((CharsChromosome) this.chromosomes[iChromIndex]).genes[iGene2];
        ((CharsChromosome) this.chromosomes[iChromIndex]).genes[iGene2] = cTemp;
    }

    /**
     * 一点交叉
     * @param Chrom1
     * @param Chrom2
     */
    @Override
    protected void doOnePtCrossover(Chromosome Chrom1, Chromosome Chrom2){
        String sNewChrom1, sNewChrom2;
        int iCrossoverPoint;
        String sChrom1, sChrom2;

        iCrossoverPoint = getRandom(chromosomeDim - 2);
        sChrom1 = Chrom1.getGenesAsStr();
        sChrom2 = Chrom2.getGenesAsStr();

        // CREATE OFFSPRING ONE
        sNewChrom1 =
            sChrom1.substring(0, iCrossoverPoint)
                + sChrom2.substring(iCrossoverPoint, chromosomeDim);

        // CREATE OFFSPRING TWO
        sNewChrom2 =
            sChrom2.substring(0, iCrossoverPoint)
                + sChrom1.substring(iCrossoverPoint, chromosomeDim);

        ((CharsChromosome) Chrom1).setGenesFromStr(sNewChrom1);
        ((CharsChromosome) Chrom2).setGenesFromStr(sNewChrom2);
    }

    /**
     * 两点交叉
     * @param Chrom1
     * @param Chrom2
     */
    @Override
    protected void doTwoPtCrossover(Chromosome Chrom1, Chromosome Chrom2){
        String sNewChrom1, sNewChrom2;
        int iCrossoverPoint1, iCrossoverPoint2;
        String sChrom1, sChrom2;

        iCrossoverPoint1 = 1 + getRandom(chromosomeDim - 2);
        iCrossoverPoint2 = iCrossoverPoint1 + 1 + getRandom(chromosomeDim - iCrossoverPoint1 - 1);

        if (iCrossoverPoint2 == (iCrossoverPoint1 + 1))
            doOnePtCrossover(Chrom1, Chrom2);
        else {
            sChrom1 = Chrom1.getGenesAsStr();
            sChrom2 = Chrom2.getGenesAsStr();

            // CREATE OFFSPRING ONE
            sNewChrom1 = sChrom1.substring(0, iCrossoverPoint1) +
                         sChrom2.substring(iCrossoverPoint1, iCrossoverPoint2) +
                         sChrom1.substring(iCrossoverPoint2, chromosomeDim);

            // CREATE OFFSPRING TWO
            sNewChrom2 = sChrom2.substring(0, iCrossoverPoint1) +
                         sChrom1.substring(iCrossoverPoint1, iCrossoverPoint2) +
                         sChrom2.substring(iCrossoverPoint2, chromosomeDim);

            ((CharsChromosome) Chrom1).setGenesFromStr(sNewChrom1);
            ((CharsChromosome) Chrom2).setGenesFromStr(sNewChrom2);
        }
    }

    /**
     * 一致交叉
     * @param Chrom1
     * @param Chrom2
     */
    @Override
    protected void doUniformCrossover(Chromosome Chrom1, Chromosome Chrom2){
        int iGeneToSwap;
        char cGene;

        StringBuffer sbChrom1 = new StringBuffer(Chrom1.getGenesAsStr());
        StringBuffer sbChrom2 = new StringBuffer(Chrom2.getGenesAsStr());

        for (int i = 0; i < chromosomeDim; i++){
            if (getRandom(100) > 50){
                iGeneToSwap = getRandom(chromosomeDim);
                cGene = sbChrom1.charAt(iGeneToSwap);

                sbChrom1.setCharAt(iGeneToSwap, sbChrom2.charAt(iGeneToSwap));
                sbChrom2.setCharAt(iGeneToSwap, cGene);
            }
        }

        ((CharsChromosome) Chrom1).setGenesFromStr(sbChrom1.toString());
        ((CharsChromosome) Chrom2).setGenesFromStr(sbChrom2.toString());
    }

}
